#include <accent/algorithms/mismatch.hpp>
#include "test_base.hpp"

TEST(Mismatch, bothEmpty_invalidPositions) {
  ivec v1 = {}, v2 = {};
  auto r1 = all(v1), r2 = all(v2);
  auto ps = mismatch(r1, r2);
  ASSERT_TRUE(!ps.first);
  ASSERT_TRUE(!ps.second);
}

TEST(Mismatch, firstEmpty_secondFrontPosition) {
  ivec v1 = {}, v2 = { 1 };
  auto r1 = all(v1), r2 = all(v2);
  auto ps = mismatch(r1, r2);
  ASSERT_TRUE(!ps.first);
  ASSERT_FALSE(!ps.second);
  ASSERT_EQ(1, *ps.second);
}

TEST(Mismatch, secondEmpty_firstFrontPosition) {
  ivec v1 = { 1 }, v2 = {};
  auto r1 = all(v1), r2 = all(v2);
  auto ps = mismatch(r1, r2);
  ASSERT_FALSE(!ps.first);
  ASSERT_TRUE(!ps.second);
  ASSERT_EQ(1, *ps.first);
}

TEST(Mismatch, equalRanges_invalidPositions) {
  ivec v1 = { 1, 2, 3 }, v2 = { 1, 2, 3 };
  auto r1 = all(v1), r2 = all(v2);
  auto ps = mismatch(r1, r2);
  ASSERT_TRUE(!ps.first);
  ASSERT_TRUE(!ps.second);
}

TEST(Mismatch, unequalRanges_mismatchPositions) {
  ivec v1 = { 1, 2, -3, 4 }, v2 = { 1, 2, 3, 4 };
  auto r1 = all(v1), r2 = all(v2);
  auto ps = mismatch(r1, r2);
  ASSERT_FALSE(!ps.first);
  ASSERT_FALSE(!ps.second);
  ASSERT_EQ(-3, *ps.first);
  ASSERT_EQ(3, *ps.second);
}

struct same_sign {
  bool operator ()(int l, int r) const { return (l < 0) == (r < 0); }
};

// 3-arg version conflicts with std

TEST(Mismatch, predicated_alwaysMatch_invalidPositions) {
  ivec v1 = { 1, -2, 3, -4 }, v2 = { 0, -99, 4, -6 };
  auto r1 = all(v1), r2 = all(v2);
  auto ps = accent::mismatch(r1, r2, same_sign());
  ASSERT_TRUE(!ps.first);
  ASSERT_TRUE(!ps.second);
}

TEST(Mismatch, predicated_dontMatch_mismatchPositions) {
  ivec v1 = { 1, -2, -3, -4 }, v2 = { 0, -99, 4, -6 };
  auto r1 = all(v1), r2 = all(v2);
  auto ps = accent::mismatch(r1, r2, same_sign());
  ASSERT_FALSE(!ps.first);
  ASSERT_FALSE(!ps.second);
  ASSERT_EQ(-3, *ps.first);
  ASSERT_EQ(4, *ps.second);
}
